import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { $message } from '@/utils/message'
import router from '@/router/'

// axios 基础配置
const config = {
	baseURL: '/dev-api/api',
	timeout: 20 * 1000 // 请求超时时间，20秒
}

// 返回值类型
export interface Result<T = any> {
	code: number
	msg: string
	data: T
}

let messageFlag = false

class Request {
	private instance: AxiosInstance

	constructor(config: AxiosRequestConfig) {
		this.instance = axios.create(config)
		this.interceptors()
	}

	// 拦截器
	interceptors() {
		// 请求拦截器
		this.instance.interceptors.request.use(
			(config) => {
				const token = localStorage.getItem('token') ?? '123456'
				if (token) {
					config.headers.Authorization = `Bearer ${token}`
				}
				return config
			},
			(error: any) => {
				error.data = {}
				error.data.msg = '服务器异常，请联系管理员！'
				return error
			}
		)

		// 响应拦截器
		this.instance.interceptors.response.use(
			(response: AxiosResponse) => {
				const { data } = response
				if (data.code == 0 || data.code == 6001) {
					// 成功
					return data
				} else if (data.code == -1) {
					// token 过期
					if (!messageFlag) {
						// 清除token
						localStorage.removeItem('token')
						const { fullPath } = router.currentRoute.value
						const query = {
							redirect: encodeURIComponent(fullPath)
						}
						$message.error('登录过期，请重新登录！')
						router.replace({
							path: '/login',
							query
						})
					}
					messageFlag = true
					return Promise.reject(data)
				} else {
					// 其他错误
					//messageInfo('error', data.msg)
					return Promise.reject(data)
				}
			},
			(error: any) => {
				// 处理网络错误，这里不是服务器响应的数据
				error.data = {}
				if (error && error.response) {
					switch (error.response.status) {
						case 400:
							error.data.msg = '请求错误'
							break
						case 401:
							error.data.msg = '未授权，请重新登录'
							break
						case 403:
							error.data.msg = '对不起，您没有权限访问'
							break
						case 404:
							error.data.msg = '请求出错，未找到请求路径'
							break
						case 405:
							error.data.msg = '请求方法未允许'
							break
						case 408:
							error.data.msg = '请求超时'
							break
						case 500:
							error.data.msg = '服务器内部错误，请重试'
							break
						case 501:
							error.data.msg = '网络未实现'
							break
						case 502:
							error.data.msg = '网络错误'
							break
						case 503:
							error.data.msg = '服务不可用'
							break
						case 504:
							error.data.msg = '网络超时'
							break
						case 505:
							error.data.msg = 'HTTP版本不支持该请求'
							break
						default:
							error.data.msg = `连接错误: CODE ${ error.response.status}`
					}
					$message.error(error.data.msg)
				} else {
					error.data.msg = '连接到服务器失败'
					$message.error(error.data.msg)
				}
				return Promise.reject(error)
			}
		)
	}

	// get 请求
	get = <T = Result>(url: string, params?: object): Promise<T> => {
		return this.instance.get(url, { params })
	}

	// post 请求
	post = <T = Result>(url: string, data?: object): Promise<T> => {
		return this.instance.post(url, data)
	}

	// put 请求
	put = <T = Result>(url: string, data?: object): Promise<T> => {
		return this.instance.put(url, data)
	}

	// delete 请求
	delete = <T = Result>(url: string, data?: object): Promise<T> => {
		return this.instance.delete(url, { data })
	}

	// 上传
	upload = <T = Result>(url: string, params?: object, callback?: Function): Promise<T> => {
		return this.instance.post(url, params, {
			onUploadProgress: (progressEvent: any) => {
				const progress = (progressEvent.progress * 100).toFixed(1)
				callback && callback(progress)
			},
			headers: {
				'Content-Type': 'multipart/form-data'
			}
		})
	}

	// 导出Excel
	exportExcel = <T = Result>(url: string, params?: object): Promise<T> => {
		const token = localStorage.getItem('token') ?? '123456'//getToken()
		return axios.get(import.meta.env.VITE_API_BASE_URL + url, {
			params,
			headers: {
				'c-token': token
			},
			responseType: 'blob'
		})
	}

	// formData post
	postForm = <T = Result>(url: string, params?: object): Promise<T> => {
		return this.instance.post(url, params, {
			headers: {
				'Content-Type': 'multipart/form-data'
			}
		})
	}
}

export default new Request(config)
